<template>
  <section>
    <header class="output-header border-rounded-top-no-bottom">
      <h4 class="text-base">JavaScript Demo: {{ props.name }}</h4>
    </header>
    <div class="mb-2">
      <codemirror
        v-model="code"
        placeholder=""
        :style="{ height: '250px' }"
        :autofocus="true"
        :indent-with-tab="true"
        :tabSize="2"
        :extensions="extensions"
      />
    </div>
    <div class="output-container">
      <div class="buttons-container">
        <div><el-button @click="runPlay()">运行</el-button></div>
      </div>
      <div class="output">
        <el-scrollbar>
          <div v-html="output"></div>
        </el-scrollbar>
      </div>
    </div>
  </section>
</template>

<script lang="ts">
import { Codemirror } from "vue-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { oneDark } from "@codemirror/theme-one-dark";

import { defineComponent, ref, onMounted } from "vue";
export default defineComponent({
  components: {
    Codemirror,
  },
  props: {
    code: String,
    name: String
  },
  setup(props) {
    onMounted(() => {
      runPlay()
    })

    const code: any = ref(props.code)
    const extensions = [javascript(), oneDark];

    const wrapOutput = function(output: any) {
          return `<span class="terminal-char">&gt;</span>${output}`;
    }

    const wrapError = function(error: any) {
        return `<span class="text-error">${error}</span>`;
    }

    let outputArr: Array<any> = []
    let outputStr: any

    let { log } = console

    const runPlay = () => {
        
        console.log = function(...args){
            let str = args.join(" ");
            log(str)
            outputArr.push(str)
        }

        try {
            (new Function(code.value))();
        } catch (e) {
            outputArr.push(wrapError(e));
        }

        outputArr = outputArr.map(function(o) {
            return wrapOutput(o);
        });
        outputStr = outputArr.join("<br>")

        output.value = outputStr

        // 把 outputArr 重置为空数组
        outputArr = [];
    };

    const output = ref()

    return {
      props,
      code,
      output,
      extensions,
      runPlay
    };
  },
});
</script>

<style lang="scss" scoped>
::v-deep .terminal-char {
    color: #b8b8b8;
    margin-right: 5px;
    user-select: none;
    -webkit-user-select: none;
}

::v-deep .text-error {
    color: #e6162d;
}

.border-rounded-top-no-bottom {
    border: solid var(--border-color);
    border-radius: var(--el-border-radius-base) var(--el-border-radius-base) 0 0;
    border-width: 1px 1px 0;
}

.output-header {
    align-items: center;
    display: flex;
    gap: 1rem;
    justify-content: space-between;
    margin: 0;
    padding: 0.5rem 1rem;
}

::v-deep .cm-editor {
    border: 1px solid var(--border-color);
}

.output, .output-container {
    display: flex;
}

.output {
    background-color: var(--bg-color-soft);
    border: 1px solid var(--border-color);
    border-radius: var(--el-border-radius-base);
    display: inline-block;
    height: 120px;
    margin: 0;
    padding: 0.8em;
    width: 100%;
}

.buttons-container {
    flex-direction: column;
    align-self: flex-start;
    display: flex;
    gap: 0.5rem;
    padding-bottom: 0.5rem;
    padding-right: 0.5rem;
}

</style>